// Copyright (c) 2023 Presto Labs Pte. Ltd.
// Author: daniel

#pragma once

#include <cstdint>
#include <functional>
#include <unordered_map>

#include "coin2/base/math/time_moving_window.h"

namespace coin::proto {
class RiskEvent;
};

namespace coin2::exchange::base::order {

class OrderContext;

// for checking the risk pending order
class RiskPendingOrder {
  class Handler {
   public:
    explicit Handler(RiskPendingOrder* risk_pending_order)
        : risk_pending_order_(risk_pending_order) {}

    template <typename P1, typename P2>
    void OnPushed(P1&& p1, P2&& p2) {
      risk_pending_order_->AddOrder(p1, p2);
    }
    template <typename P1, typename P2>
    void OnPopped(P1&& p1, P2&& p2) {
      risk_pending_order_->DelOrder(p1, p2);
    }
    void OnClear() {}

   private:
    RiskPendingOrder* risk_pending_order_;
  };

 public:
  using MovingWindow = coin2::base::math::TimeMovingWindow<int64_t, Handler>;
  using RiskEventHandler = std::function<void(const coin::proto::RiskEvent&)>;

 public:
  explicit RiskPendingOrder(int threshold, int64_t window_size);

  void HandleOrderTimedout(int64_t ts, const OrderContext& oc);
  void HandleOrderVerified(int64_t ts, const OrderContext& oc);
  void ManageRisk(int64_t ts);
  void RegisterRiskEventHandler(RiskEventHandler risk_event_handler) {
    risk_event_handler_ = risk_event_handler;
  }

 protected:
  void AddOrder(int64_t ts, int64_t proc_order_id);
  void DelOrder(int64_t ts, int64_t proc_order_id);
  void Update(int64_t ts);
  void HandleRiskEvent(int risk_pending_order_cnt);

 private:
  int risk_pending_order_threshold_ = 0;
  MovingWindow pending_order_window_;
  std::unordered_map<int64_t, int64_t> pending_orders_;
  int64_t last_update_timestamp_ = 0;
  RiskEventHandler risk_event_handler_;
};

}  // namespace coin2::exchange::base::order
